/*:
 * @plugindesc (v1.21)寵物系統
 * @author 小c
 * @version 1.2.1
* @date 4/18/2020
*
* @param Base Params
* @text ---- 基本數據訊息 ----
*
* @param Pet Added Code
* @text 添加寵物額外代碼
* @parent Base Params
* @type note
* @desc 寵物添加時執行的額外代碼，比如自動出戰
* @default "//pet.addState(15);"
*
* @param Pet Exit Time
* @text 寵物死亡退場時間
* @parent Base Params
* @type number
* @min 0
* @desc 寵物退場死亡時的消失時間【幀】，0表示不消失。
* @default 60
*
* @param Pet Change Code
* @text 寵物替換額外代碼
* @parent Base Params
* @type note
* @desc 寵物替換時執行的額外代碼
* @default "//變量oldPet表示下場寵物，newPet表示新進場寵物\n//oldItem和newItem分別表示他們對應的召喚物品或技能"
*
* @param Pet Die Code
* @text 寵物死亡額外代碼
* @parent Base Params
* @type note
* @desc 寵物死亡時執行的額外代碼，比如直接退場
* @default "pet.rest();\npet.removeState(pet.deathStateId());"
*
* @param Battle Ended Code
* @text 戰鬥結束額外代碼
* @parent Base Params
* @type note
* @desc 戰鬥結束時執行的額外代碼，比如移除寵物
* @default "//此處this指向$gameParty"
*
* @param Pet Auto Battle
* @text 寵物自動戰鬥
* @parent Base Params
* @type boolean
* @on 自動戰鬥
* @off 手動操作
* @desc 寵物默認是否自動戰鬥，如果為false，是否自動戰鬥取決於寵物屬性
* @default false
*
* @param Pet AI Level
* @text 寵物AI等級
* @parent Base Params
* @type number
* @min 0
* @max 100
* @desc 寵物AI等級，標準參考YEP_BattleAICore
* @default 80
*
* @param Default Pet Class
* @text 寵物默認職業
* @parent Base Params
* @type class
* @desc 寵物默認關聯職業
* @default 0
*
* @param Pet Max Level
* @text 寵物最高等級
* @parent Base Params
* @type number
* @min 1
* @desc 默認寵物最高等級
* @default 99
*
* @param Max Pets Number
* @text 寵物最大數量
* @parent Base Params
* @type number
* @min 1
* @desc 隊伍中寵物數量，包括不出戰寵物，不包括倉庫。
* @default 5
*
* @param Max Battle Pets Number
* @text 戰鬥寵物最大數量
* @parent Base Params
* @type number
* @min 1
* @desc 隊伍中出戰寵物數量。
* @default 5
*
* @param Defeat When Only Pets Alive
* @text 僅剩寵物存活時判定戰鬥失敗
* @parent Base Params
* @type boolean
* @on 是
* @off 否
* @desc 隊伍全滅僅剩寵物時是否認定為全滅【戰鬥失敗】
* @default false
*
* @param Pet Sprite Position
* @text 召喚寵物座標
* @parent Base Params
* @type note
* @desc 寵物的顯示位置，master表示召喚者
* @default "x = master.x - 96 * index;\ny = master.y + 12 * index;"
*
* @param Reset All Pets Master
* @text 重置寵物召喚者
* @parent Base Params
* @type boolean
* @on 重置
* @off 不重置
* @desc 每場戰鬥開始前重置每個寵物的召喚者使其更加均勻
* 置為true時AddPet中的masterId將失去作用（每場戰鬥都會自動重置master）
* @default true
*
* @param Scene Params
* @text ---- 界面數據訊息 ----
*
* @param Use This Scene
* @text 使用此界面
* @parent Scene Params
* @type boolean
* @on 使用
* @off 不使用
* @desc 是否使用默認UI
* @default true
*
* @param Change Window Data
* @text 寵物替換视窗屬性
* @parent Scene Params
* @type struct<ChangeWindow>
* @desc 寵物替換選擇视窗的屬性，此參數必需，且與默認UI無關
* @default {"x":"Graphics.boxWidth / 2 - 150","y":"Graphics.boxHeight / 2 - 100","width":"300","height":"200","text":"要替換哪個寵物？"}
*
* @param Change Select Callback Code
* @text 寵物替換视窗選擇回調代碼
* @parent Scene Params
* @type note
* @desc this指針為該替換视窗
* @default "var pet = this.currentPet();\nif(!!pet)\n  $gameParty.select(pet);\nelse\n  $gameParty.select(null);"
* 
* @param Pet Command Name
* @text 寵物選單名稱
* @parent Scene Params
* @desc 主選單中寵物系統的選單名稱
* @default 寵物
*
* @param Help Window Text
* @text 幫助视窗顯示文字
* @parent Scene Params
* @desc 顯示在幫助视窗中的文字訊息
* @default 寵物信息系統。
*
* @param Fight Help Text
* @text 出戰提示文字
* @parent Scene Params
* @desc 寵物出戰時的提示訊息
* @default %1已出戰！奧利給！
*
* @param Rest Help Text
* @text 休息提示文字
* @parent Scene Params
* @desc 寵物休息時的提示訊息
* @default %1下場休息了，感謝他的貢獻！
*
* @param Depository In Help Text
* @text 存倉庫提示文字
* @parent Scene Params
* @desc 寵物存倉庫時的提示訊息
* @default %1已存入倉庫，讓我們歡送他！
*
* @param Depository Out Help Text
* @text 取倉庫提示文字
* @parent Scene Params
* @desc 寵物存倉庫時的提示訊息
* @default %1已從倉庫取出，讓他和我們並肩作戰！
*
* @param Release Help Text
* @text 放生提示文字
* @parent Scene Params
* @desc 寵物放生時的提示訊息
* @default %1已放生，他自由了！
*
* @param Type Window Width
* @text 左側视窗寬度
* @parent Scene Params
* @desc 寵物類型视窗寬度公式
* @default Graphics.boxWidth / 4
*
* @param Type Window Height Plus
* @text 寵物類型视窗高度修正值
* @parent Scene Params
* @type number
* @desc 寵物類型视窗高度調整值，默認為0表示高度為兩行文字的高度
* @default 0
*
* @param Status Window Height
* @text 狀態视窗高度
* @parent Scene Params
* @desc 寵物簡單狀態视窗高度公式，this指向scene
* @default this._typeWindow.height * 2
*
* @param Command Window Height Plus
* @text 命令视窗高度修正值
* @parent Scene Params
* @type number
* @desc 命令视窗高度修正值，默認為0吧=表示高度為一行文字的高度，此视窗變高會導致訊息视窗高度降低
* @default 0
*
* @param Pet List Name
* @text 寵物類型指令名稱
* @parent Scene Params
* @desc 寵物列表指令的顯示名稱
* @default 寵物
*
* @param Pet Depository Name
* @text 寵物倉庫指令名稱
* @parent Scene Params
* @desc 寵物倉庫指令的顯示名稱
* @default 倉庫
*
* @param Show Pet Level
* @text 顯示寵物等級
* @parent Scene Params
* @type boolean
* @on 顯示
* @off 不顯示
* @desc 寵物列表及替換列表顯示寵物等級
* @default true
*
* @param Pet Level Name
* @text 寵物【等級】顯示名稱
* @parent Scene Params
* @desc 寵物列表中寵物等級的表述文字
* @default 等級 
*
* @param Pet List Battle Color
* @text 出戰寵物文字顏色
* @parent Scene Params
* @type number
* @min 0
* @desc 寵物列表中處於出戰狀態的寵物的文字顏色
* @default 6
*
* @param Fight Rest Command Useable
* @text 出戰、休息指令可用性
* @parent Scene Params
* @type boolean
* @on 可用
* @off 不可用
* @desc 命令视窗出戰、休息的可用性，有些情況下不允許在戰鬥外改變戰鬥狀態，請禁止
* @default true
*
* @param Pet Command Fight Name
* @text 寵物出戰指令名稱
* @parent Scene Params
* @desc 寵物出戰指令名稱
* @default 出戰
*
* @param Pet Command Rest Name
* @text 寵物休息指令名稱
* @parent Scene Params
* @desc 寵物休息指令名稱
* @default 休息
*
* @param Pet Command In Depository Name
* @text 寵物存倉庫指令名稱
* @parent Scene Params
* @desc 寵物存倉庫指令名稱
* @default 存入倉庫
*
* @param Pet Command Out Depository Name
* @text 寵物取倉庫指令名稱
* @parent Scene Params
* @desc 寵物取倉庫指令名稱
* @default 取出倉庫
*
* @param Pet Command Release Name
* @text 寵物放生指令名稱
* @parent Scene Params
* @desc 寵物放生指令名稱
* @default 放生
*
* @param Release Confirm Info
* @text 放生確認訊息
* @parent Scene Params
* @desc 寵物放生時提示框的提示訊息
* @default 確認放生寵物%1嗎？放生後無法找回！
*
* @param Release Confirm Yes Info
* @text 放生確認指令名稱
* @parent Scene Params
* @desc 放生確認视窗中確認的指令名稱
* @default 確定
*
* @param Release Confirm No Info
* @text 放生取消指令名稱
* @parent Scene Params
* @desc 放生確認视窗中取消的指令名稱
* @default 取消
*
* @param Release Confirm X Offset
* @text 放生確認视窗X偏移量
* @parent Scene Params
* @type number
* @desc 此偏移量越大。视窗右移越大
* @default -100
*
* @param Release Confirm Y Offset
* @text 放生確認视窗Y偏移量
* @parent Scene Params
* @type number
* @desc 此偏移量越大。视窗右移越大
* @default 0
*
* @param Detail Item Width
* @text 訊息视窗項目密度
* @parent Scene Params
* @type number
* @desc 訊息视窗顯示項目的密度，數據越大項目越緊密
* @default 24
* 
 * @help
 * 寵物系統，以敵人為標準構建隊友。
 * 注意：寵物隊友【不可以】通過整隊指令調整順序
 * 若使用YEP_BattleAICore，請將此插件放在它的下面，寵物AI才會正常運行。
 * 若使用YEP_BuffsStatesCore 請將此插件放在它的下面。
 * 若使用KEL_DragonbonesIntegration或KELYEP龍骨插件，請使用本插件的1.18或以
 * 上版本。
 *
 * 本插件預留的代碼接口如下：
 * 寵物召喚入場 寵物死亡退場 寵物替換 戰鬥結束
 * 前兩者有敵人標籤可設定新代碼，當沒有標籤時以插件參數為準
 * 後兩者僅可通過插件參數修改。
 *
 * 注意：使用插件時務必將寵物職業指定好。
 *
 * 敵人標籤
 * 職業
 * <Pet Class: x> 寵物關聯職業
 * 沒有此標籤，關聯職業以插件參數為準
 * 關聯職業影響寵物附屬屬性，裝備槽等。
 * <Pet Class Affect Param> 寵物屬性由職業決定
 * 默認寵物基礎屬性與職業無關
 *
 * 圖片
 * <Pet Character: name, index>寵物的角色圖
 * <Pet Face: name, index> 寵物臉圖
 * <Pet Battler: name> 角色戰鬥圖
 *
 * 等級 裝備
 * <Pet Init Level: x> 寵物初始等級為x
 * <Pet Max Level: x> 最大等級為x
 * <Pet Init Equips: x, x, x>寵物初始裝備組，其按裝備槽順序配置
 * <Pet Init Equips: 1, 1, 2, 3, 4>
 * 表示裝備為：武器1 防具1 防具2 防具3 防具4
 * 0表示沒有裝備
 *
 * 基礎屬性
 * <Custom Pet Params>
 * mhp = base.mhp + 10 * level;
 * mmp = base.atk;
 * </Custom Pet Params>
 * 自定義基礎屬性，base對象儲存了在敵人數據庫的數據
 * level表示當前寵物等級
 *
 * 召喚寵物座標
 * <Pet Sprite Position>
 * x = master.x - 80 * index;
 * y = master.y + 12 * index;
 * </Pet Sprite Position>
 * 其中 index 表示當前寵物在主人寵物隊列的位置。
 * 即【此寵物是主人召喚的第index個寵物】
 * 插件參數中也可以使用此index
 *
 * <Default Pet Position> 採用系統默認座標
 *
 * 自動戰鬥
 * <Pet Auto Battle> 寵物自動戰鬥
 * 沒有此標籤以插件參數為準，若最終值為false，是否自動戰鬥取決於角色屬
 * 性
 * 
 * <Pet AI Level: x>寵物AI等級
 * <Pet AI Priority>
 * ai list
 * </Pet AI Priority>
 * 寵物AI配置，AI序列參見YEP_BattleAICore
 * 此標籤需YEP_BattleAICore支持
 *
 * 寵物入場
 * <Pet Added Code>
 * //JavaScript code
 * $gameParty.gainGold(1000);
 * </Pet Added Code>
 * 寵物入場時執行額外代碼
 * 包括物品/技能召喚以及插件指令入場等
 * 沒有標籤將執行插件參數
 *
 * 寵物死亡
 * <Pet Exit Time: x> 寵物退場消失時間，單位【幀】
 * 指定時間後寵物消失，執行死亡代碼
 * 若時間為0，則不消失，直接執行死亡代碼
 *
 * <Pet Die Code>
 * //JavaScript code
 * pet.rest();
 * </Pet Die Code>
 * 寵物死亡時的響應代碼
 *
 * 技能 物品標籤
 * <Add Pet Enemy ID: x> 指定技能物品召喚的寵物對應的敵人id
 *
 * 角色變量修正
 * YEP角色變量對角色的配置同時對寵物生效
 * 角色變量插件在Actor上的標籤若配置在Enemy中對寵物有效
 * 寵物角色變量的默認值以YEP角色變量插件的參數為準
 *
 * 插件指令
 * ShowPetScene 顯示寵物界面【Scene_Pet】
 * 如果不使用默認界面，請自行構建此Scene，否則調用此插件指令會出錯
 * AddPet enemyId [masterId] [autoFight] 召喚指定敵人的寵物
 * enemyId 必需，指定寵物的基礎敵人編號
 * masterId 可選，此寵物的召喚者，未指定時為我方第一人
 * autoFight 可選，召喚完成即進入戰鬥隊列
 * 例：AddPet 2 2 autoFight
 *
 * DefeatWhenPetsAlive true / false
 * 只剩寵物存活時是否認定戰鬥失敗的設定修改
 * 例：DefeatWhenPetsAlive true
 *
 * 注意：
 * 戰鬥中當場上寵物數量滿時會調出替換视窗。
 * 參數中【寵物替換视窗選擇代碼】會在替換视窗select函數執行的時候同時執
 * 行。
 * 該參數默認值：在橫版戰鬥中，玩家選擇的對應寵物的戰鬥圖會閃動。
 * 當寵物數量滿時將無法以任何形式召喚寵物
 * 若你希望戰鬥中可使用召喚物替換寵物，【寵物最大數量】必須大於【戰鬥寵
 * 物最大數量】
 *
 * JS函數
 * pet = $gameParty.addPet(enemyId, masterId)
 * 添加以指定敵人為基準的寵物，返回值為寵物id
 * $gameActors.actor(petId) 可以得到這個寵物
 * 若寵物已滿，此函數會拋出錯誤
 *
 * $gameParty.battleMembersNotPets() 得到除了寵物之外的戰鬥者
 * $gameParty.pets() 得到所有寵物對象，包括未出戰寵物，不包括倉庫
 * $gameParty.battlePets() 得到所有出戰寵物對象
 * $gameParty.aliveBattleActors() 得到所有存活的非寵物角色
 * 
 * $gameParty.clearPets() 清除【放生】所有寵物
 * $gameParty.clearAllPets() 清除【放生】所有寵物【包括倉庫】
 *
 * pet.baseItem() 返回寵物對象的召喚物品/技能/裝備
 *
 * 更新日誌
 * v1.00
 * 插件完成
 *
 * v1.01
 * 新增寵物自動戰鬥AI配置，需YEP_BattleAICore支持
 *
 * v1.02
 * 追加寵物出場、死亡時的自定義代碼
 * 使用者可禁止寵物界面中【出戰】【休息】指令
 *
 * v1.03
 * 修復本插件與YEP動作序列衝突的問題
 * 引入僅剩寵物時判定戰鬥失敗的設定
 *
 * v1.04
 * 增加抓捕寵物的功能
 *
 * v1.05
 * 修復橫版戰鬥時角色站位錯誤的問題
 * 添加召喚寵物替換已有寵物的功能
 * 注意：如果寵物數已滿，再次召喚寵物時，被替換的寵物將被放生，永久消失
 *
 * v1.06
 * 修復選擇视窗響應取消異常的問題
 * 寵物滿時替換寵物，舊寵物將存入倉庫而不是放生
 * 增加寵物替換時的響應接口
 *
 * v1.07
 * 添加顯示寵物界面的插件指令
 *
 * v1.08
 * 解決與YEP角色變量插件的衝突問題
 * 添加類型视窗和命令视窗高度的調整參數
 * 解決與本人插件CP_UseEquip的兼容性問題
 *
 * v1.09
 * 倉庫中的寵物被修改為禁止放生
 *
 * v1.10
 * 兼容FTKR的技能樹系統
 *
 * v1.11
 * 取消所有捕捉寵物的內容
 * 捕捉寵物請使用CP_X_CatchEnemyGainPet
 * 對YEP_PartySystem和CP_ClassExp進行兼容
 *
 * v1.12
 * 修復在使用YEP_PartySystem戰鬥嚴重掉幀的問題
 *
 * v1.13
 * 修復寵物通過整隊指令調整順序死機的問題
 * 寵物不允許整隊調整順序
 *
 * v1.14
 * 修復寵物默認AI錯誤的bug
 *
 * v1.15
 * 追加戰鬥中替換寵物時選擇寵物的響應代碼
 *
 * v1.16
 * 修復YEP_ClassChangeCore導致添加寵物死機的bug
 *
 * v1.17
 * 適配GT套裝插件，套裝效果對寵物生效
 * 修復使用YEP狀態核心時無法獲取origin對象的問題
 *
 * v1.18
 * 對龍骨插件KEL_DragonbonesIntegration以及YEPKEL龍骨插件提供支持
 * 此處特別感謝chyj4747大佬的幫助
 *
 * v1.19
 * 解決未使用YEPAI核心時寵物自動戰鬥崩潰的問題
 *
 * v1.20
 * 修復替換寵物會因不滿足條件執行失敗的問題
 * 不滿足條件時召喚不可用
 * 修復替換寵物cancel響應錯誤的問題
 *
 * v1.21
 * 修改寵物存在某技能即存在該技能類型
 */
/*~struct~ChangeWindow:
 * @param x
 * @text 视窗x座標
 * @default Graphics.boxWidth / 2 - 150
 * @parent Object Selectors
 *
 * @param y
 * @text 视窗y座標
 * @default Graphics.boxHeight / 2 - 100
 * @parent Object Selectors
 *
 * @param width
 * @text 视窗寬度
 * @default 300
 * @parent Object Selectors
 *
 * @param height
 * @text 视窗高度
 * @default 200
 * @parent Object Selectors
 *
 * @param text
 * @text 视窗提示訊息
 * @desc 選擇替換寵物時的提示訊息
 * @default 要替換哪個寵物？
 *
 */

var Imported = Imported || {};
Imported.CP_PetCore = true;

var params = PluginManager.parameters("CP_PetCore");

var CP = CP || {};
CP.PetManager = CP.PetManager || {};

CP.PetManager._catchAction = null;

CP.PetManager.PET_EXIT_TIME = Number(params["Pet Exit Time"]) || 0;
CP.PetManager.PET_ADDED_CODE = JSON.parse(params["Pet Added Code"]);
CP.PetManager.PET_CHANGE_CODE = JSON.parse(params["Pet Change Code"]);
CP.PetManager.PET_DIE_CODE = JSON.parse(params["Pet Die Code"]);
CP.PetManager.BATTLE_ENDED_CODE = JSON.parse(params["Battle Ended Code"]);
CP.PetManager.PET_AI_LEVEL = Number(params["Pet AI Level"]) || 0;
CP.PetManager.DEFAULT_PET_CLASS = Number(params["Default Pet Class"]) || 0;
CP.PetManager.MAX_PETS_NUMBER = Number(params["Max Pets Number"]) || 1;
CP.PetManager.MAX_BATTLE_PETS_NUMBER = Number(params["Max Battle Pets Number"]) || 1;
if(CP.PetManager.MAX_BATTLE_PETS_NUMBER > CP.PetManager.MAX_PETS_NUMBER)
	CP.PetManager.MAX_BATTLE_PETS_NUMBER = CP.PetManager.MAX_PETS_NUMBER;
CP.PetManager.MAX_PET_LEVEL = Number(params["Pet Max Level"]) || 1;
CP.PetManager.PET_AUTO_BATTLE = eval(params["Pet Auto Battle"]) || false;
CP.PetManager.DEFEAT_WHEN_ONLY_PETS_ALIVE = eval(params["Defeat When Only Pets Alive"]) || false;
CP.PetManager.RESET_ALL_PETS_MASTER = eval(params["Reset All Pets Master"]) || false;

CP.PetManager.PET_SPRITE_POSITION = JSON.parse(params["Pet Sprite Position"]);

CP.PetManager.USE_SCENE = eval(params["Use This Scene"]);
CP.PetManager.SHOW_PET_LEVEL = eval(params["Show Pet Level"]) || false;
CP.PetManager.FIGHT_REST_COMMAND_USABLE = eval(params["Fight Rest Command Useable"]) || false;
CP.PetManager.HELP_WINDOW_TEXT = params["Help Window Text"];
CP.PetManager.PET_COMMAND_NAME = params["Pet Command Name"];
CP.PetManager.TYPE_WINDOW_WIDTH = params["Type Window Width"];
CP.PetManager.TYPE_WINDOW_HEIGHT_PLUS = Number(params["Type Window Height Plus"]) || 0;
CP.PetManager.STATUS_WINDOW_HEIGHT = params["Status Window Height"];
CP.PetManager.COMMAND_WINDOW_HEIGHT_PLUS = Number(params["Command Window Height Plus"]) || 0;

CP.PetManager.FIGHT_HELP_TEXT = params["Fight Help Text"];
CP.PetManager.REST_HELP_TEXT = params["Rest Help Text"];
CP.PetManager.DEPOSITORY_IN_HELP_TEXT = params["Depository In Help Text"];
CP.PetManager.DEPOSITORY_OUT_HELP_TEXT = params["Depository Out Help Text"];
CP.PetManager.RELEASE_HELP_TEXT = params["Release Help Text"];

CP.PetManager.PET_LIST_NAMES = new Array(2);
CP.PetManager.PET_LIST_NAMES[0] = params["Pet List Name"];
CP.PetManager.PET_LIST_NAMES[1] = params["Pet Depository Name"];
CP.PetManager.PET_LEVEL_NAME = params["Pet Level Name"];
CP.PetManager.PET_LIST_BATTLE_COLOR = Number(params["Pet List Battle Color"]) || 0;

CP.PetManager.PET_COMMAND_FIGHT_NAME = params["Pet Command Fight Name"];
CP.PetManager.PET_COMMAND_REST_NAME = params["Pet Command Rest Name"];
CP.PetManager.PET_COMMAND_IN_DEPOSITORY_NAME = params["Pet Command In Depository Name"];
CP.PetManager.PET_COMMAND_OUT_DEPOSITORY_NAME = params["Pet Command Out Depository Name"];
CP.PetManager.PET_COMMAND_RELEASE_NAME = params["Pet Command Release Name"];
CP.PetManager.RELEASE_CONFIRM_INFO = params["Release Confirm Info"];
CP.PetManager.RELEASE_CONFIRM_X_OFFSET = Number(params["Release Confirm X Offset"]) || 0;
CP.PetManager.RELEASE_CONFIRM_Y_OFFSET = Number(params["Release Confirm Y Offset"]) || 0;

CP.PetManager.RELEASE_CONFIRM_COMMAND_INFOS = new Array(2);
CP.PetManager.RELEASE_CONFIRM_COMMAND_INFOS[0] = params["Release Confirm Yes Info"];
CP.PetManager.RELEASE_CONFIRM_COMMAND_INFOS[1] = params["Release Confirm No Info"];

CP.PetManager.DETAIL_ITEM_WIDTH = Number(params["Detail Item Width"]) || 0;

CP.PetManager.CHANGE_WINDOW_DATA = JSON.parse(params["Change Window Data"]);
CP.PetManager.CHANGE_SELECT_CALLBACK = JSON.parse(params["Change Select Callback Code"]);

CP.PetManager._loaded = false;
CP.PetManager.DATABASE_LOADED = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function(){
	if(!CP.PetManager.DATABASE_LOADED.call(this)) return false;

	CP.PetManager.loadPetAdd();
	CP.PetManager.loadPetHomePosition();
	CP.PetManager.loadPetEquips();
	CP.PetManager.loadPetLevelAndClass();
	CP.PetManager.loadPetImages();
	CP.PetManager.loadPetCustomParam();
	CP.PetManager.loadPetDie();
	if(Imported.YEP_BattleAICore)
		CP.PetManager.loadPetAI();

	CP.PetManager.loadItemSkillPetAdded($dataItems);
	CP.PetManager.loadItemSkillPetAdded($dataSkills);

	if(!CP.PetManager._loaded){
		if(Imported.YEP_X_ActorVariables)
			this.processAVarNotetags($dataEnemies);
		if(Imported.FTKR_STS)
			this.stsTreeListNotetags($dataEnemies);

		CP.PetManager._loaded = true;
	}

	return true;
};

CP.PetManager.loadPetHomePosition = function(){
	var reg = /<Pet Sprite Position>([\s\S]+)<\/Pet Sprite Position>/;
	for(var i = 1; i < $dataEnemies.length; i++){
		var pet = $dataEnemies[i];
		pet.defaultPetPosition = false;
		pet.homePosition = CP.PetManager.PET_SPRITE_POSITION;

		if(Imported.YEP_BattleEngineCore){
			pet.anchorX = Yanfly.Param.BECAnchorX;
			pet.anchorY = Yanfly.Param.BECAnchorY;
		}

		if(pet.meta["Default Pet Position"])
			pet.defaultPetPosition = true;

		if(reg.exec(pet.note)){
			pet.homePosition = RegExp.$1;
		}
	}
}

CP.PetManager.loadPetEquips = function(){
	for(var i = 1; i < $dataEnemies.length; i++){
		var pet = $dataEnemies[i];
		pet.equips = new Array($dataSystem.equipTypes.length - 1);
		var equips = pet.meta["Pet Init Equips"];
		if(equips)
			equips = equips.split(",");

		for(var j = 0; j < pet.equips.length; j++){
			if(equips && equips[j])
				pet.equips[j] = Number(equips[j]) || 0;
			else
				pet.equips[j] = 0;
		}
	}
};

CP.PetManager.loadPetLevelAndClass = function(){
	for(var i = 1; i < $dataEnemies.length; i++){
		var pet = $dataEnemies[i];
		pet.petClassId = CP.PetManager.DEFAULT_PET_CLASS;
		pet.classAffectParam = false;
		pet.initLevel = 1;
		pet.petMaxLevel = CP.PetManager.MAX_PET_LEVEL;
		pet.petAutoBattle = CP.PetManager.PET_AUTO_BATTLE;
		
		if(pet.meta["Pet Class"])
			pet.petClassId = Number(pet.meta["Pet Class"]) || 0;
		if(pet.petClassId > 0 && pet.meta["Pet Class Affect Param"])
			pet.classAffectParam = true;

		if(pet.meta["Pet Init Level"])
			pet.initLevel = Number(pet.meta["Pet Init Level"]) || 0;
		if(pet.meta["Pet Max Level"])
			pet.petMaxLevel = Number(pet.meta["Pet Max Level"]) || 0;
		if(pet.meta["Pet Auto Battle"])
			pet.petAutoBattle = true;
	}
};

CP.PetManager.loadPetCustomParam = function(){
	var reg = /<Custom Pet Params>([\s\S]*)<\/Custom Pet Params>/;
	for(var i = 1; i < $dataEnemies.length; i++){
		var pet = $dataEnemies[i];

		pet.customParamCode = null;

		if(reg.exec(pet.note))
			pet.customParamCode = RegExp.$1;
	}
};

CP.PetManager.loadPetImages = function(){
	for(var i = 1; i < $dataEnemies.length; i++){
		var pet = $dataEnemies[i];
		this.loadPetCharacter(pet);
		this.loadPetFace(pet);
		this.loadPetBattler(pet);
	}
};

CP.PetManager.loadPetCharacter = function(pet){
	pet.characterName = "";
	pet.characterIndex = 0;

	var reg = /<Pet Character: ([\S\s]+?), (\d+)>/;
	if(reg.exec(pet.note)){
		pet.characterName = RegExp.$1;
		pet.characterIndex = Number(RegExp.$2) || 0;
	}
};

CP.PetManager.loadPetFace = function(pet){
	pet.faceName = "";
	pet.faceIndex = 0;

	var reg = /<Pet Face: ([\S\s]+?), (\d+)>/;
	if(reg.exec(pet.note)){
		pet.faceName = RegExp.$1;
		pet.faceIndex = Number(RegExp.$2) || 0;
	}
};

CP.PetManager.loadPetBattler = function(pet){
	pet.petBattlerName = "";

	if(pet.meta["Pet Battler"])
		pet.petBattlerName = pet.meta["Pet Battler"].trim();
};

CP.PetManager.loadItemSkillPetAdded = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];
		item.petAddedInfo = null;

		if(item.meta["Add Pet Enemy ID"]){
			if(!item.petAddedInfo)
				item.petAddedInfo = {};
			item.petAddedInfo.enemyId = Number(item.meta["Add Pet Enemy ID"]) || 0;
			item.petAddedInfo.animationId = Number(item.meta["Add Pet Animation"]) || 0;
		}
	}
};

CP.PetManager.loadPetAdd = function(){
	var reg = /<Pet Added Code>([\s\S]+)<\/Pet Added Code>/;
	for(var i = 1; i < $dataEnemies.length; i++){
		var pet = $dataEnemies[i];
		pet.petAddedCode = CP.PetManager.PET_ADDED_CODE;
		pet.canBeCaught = true;

		if(reg.exec(pet.note))
			pet.petAddedCode = RegExp.$1;

		if(pet.meta["Cannot Be Caught"])
			pet.canBeCaught = false;
	}
};

CP.PetManager.loadPetDie = function(){
	var reg = /<Pet Die Code>([\s\S]+)<\/Pet Die Code>/;
	for(var i = 1; i < $dataEnemies.length; i++){
		var pet = $dataEnemies[i];
		pet.petDieCode = CP.PetManager.PET_DIE_CODE;
		pet.petExitTime = CP.PetManager.PET_EXIT_TIME;

		if(pet.meta["Pet Exit Time"])
			pet.petExitTime = Number(pet.meta["Pet Exit Time"]) || 0;

		if(reg.exec(pet.note))
			pet.petDieCode = RegExp.$1;
	}
};

CP.PetManager.loadPetAI = function(){
	var reg = /<Pet AI Priority>\n([\s\S]+)\n<\/Pet AI Priority>/;
	for(var i = 1; i < $dataEnemies.length; i++){
		var pet = $dataEnemies[i];
		pet.petAiPattern = pet.aiPattern;
		pet.petAiLevel = CP.PetManager.PET_AI_LEVEL;

		if(pet.meta["Pet AI Level"])
			pet.petAiLevel = Number(pet.meta["Pet AI Level"]) || 0;
		pet.petAiLevel *= 0.01;

		if(reg.exec(pet.note)){
			pet.petAiPattern = RegExp.$1.split("\n");
		}
	}
};

CP.PetManager.setCatchAction = function(action){
	this._catchAction = action;
};

CP.PetManager.catchAction = function(){
	return this._catchAction;
};

CP.PetManager.isAddPetItem = function(item){
	if(item && Imported.CP_UseEquip)
		item = CP.UseEquipManager.getRealUseItem(item);

	if(!DataManager.isItem(item) && !DataManager.isSkill(item))
		return false;

	if(item.petAddedInfo && item.petAddedInfo.enemyId > 0)
		return true;

	return false;
};

CP.PetManager.canUseAddPetItem = function(item){
	var petActionCount = BattleManager.petActionNum();
    if($gameParty.pets().length + petActionCount >= $gameParty.maxPets())
        return false; //當全體寵物量+待召喚指令達到上限
	else if($gameParty.battlePets().length + petActionCount >= $gameParty.maxBattlePets()){
		if($gameParty.battlePets().length === $gameParty.maxBattlePets() && petActionCount > 1)
			return false; //玩家已有召喚物太多
		else if($gameParty.battlePets().length < $gameParty.maxBattlePets())
			return false; //玩家待上召喚物太多
        else
            return true;
	}else
        return true;
};

//--------------------------------
// BattleManager
//---------------------------------
CP.PetManager.SETUP_BATTLE = BattleManager.setup;
BattleManager.setup = function(troopId, canEscape, canLose){
	if(CP.PetManager.RESET_ALL_PETS_MASTER)
		$gameParty.resetAllPetsOrder();

	$gameParty.battleMembersNotPets().forEach(function(actor){
		actor.orderPets();
	});

	CP.PetManager.SETUP_BATTLE.call(this, troopId, canEscape, canLose);
};

BattleManager.petActionNum = function(){
	var num = 0;

	$gameParty.battleMembers().forEach(function(actor){
		var action = actor.currentAction();
		if(action && action.isAddPetAction())
			num++;
	});

	return num;
};

if(!Imported.YEP_BattleEngineCore){

BattleManager.registerSprite = function(battler, sprite) {
  if (!this._registeredSprites) this._registeredSprites = {};
  if (battler.isActor()) var id = 100000 + battler.actorId();
  if (battler.isEnemy()) var id = 200000 + battler.index();
  this._registeredSprites[id] = sprite;
};

BattleManager.getSprite = function(battler) {
  if (!this._registeredSprites) this._registeredSprites = {};
  if (battler.isActor()) var id = 100000 + battler.actorId();
  if (battler.isEnemy()) var id = 200000 + battler.index();
  return this._registeredSprites[id];
};

//---------------------------------
//   Game_Battler
//--------------------------------
Game_Battler.prototype.setBattler = function(sprite){
	BattleManager.registerSprite(this, sprite);
};

Game_Battler.prototype.battler = function(){
	return BattleManager.getSprite(this);
};
}

Game_Battler.prototype.isPet = function(){
	return false;
};

//--------------------------------
// Game_Actors
//---------------------------------
Game_Actors.prototype.isPetId = function(actorId){
	return actorId >= $dataActors.length;
};

Game_Actors.prototype.newPetId = function() {
    var id = $dataActors.length;
    while(!!this._data[id]) id++;
    return id;
};

CP.PetManager.ACTORS_ACTOR = Game_Actors.prototype.actor;
Game_Actors.prototype.actor = function(actorId) {
    if (this.isPetId(actorId)) return this._data[actorId];
    return CP.PetManager.ACTORS_ACTOR.call(this, actorId);
};

Game_Actors.prototype.addPet = function(enemyId) {
    var petId = this.newPetId();
    this._data[petId] = new Game_Pet(petId, enemyId);
    return petId;
};

Game_Actors.prototype.deletePet = function(petId){
	if(!this.isPetId(petId))
		return false;

	this._data[petId] = null;
	return true;
};


if(Imported.YEP_BuffsStatesCore){

CP.PetManager.BATTLER_SET_STATE_ORIDIN = Game_BattlerBase.prototype.setStateOrigin;
Game_BattlerBase.prototype.setStateOrigin = function(stateId, battler){
    if(this._stateOrigin === undefined) this._stateOrigin = {};
    if(!$gameParty.inBattle()) return;
    if(!battler) {
      battler = BattleManager._subject;
      if(!battler) return;
    }
    if(battler.isPet())
    	this.setStateOriginForPet(stateId, battler);
    else
    	CP.PetManager.BATTLER_SET_STATE_ORIDIN.call(this, stateId, battler);
};

Game_BattlerBase.prototype.setStateOriginForPet = function(stateId, battler){
	if(!battler.isPet())
		return;
	var arr = [2, battler.petId()];
	this._stateOrigin[stateId] = arr;
};

Game_BattlerBase.prototype.stateOrigin = function(stateId) {
    if (this._stateOrigin === undefined) this._stateOrigin = {};
    if (!this._stateOrigin[stateId]) return this;
    var arr = this._stateOrigin[stateId];
    if ([0, 2].contains(arr[0])) return $gameActors.actor(arr[1]);
    if (arr[0] === 1) return $gameTroop.members()[arr[1]];
    return this;
};

}
//---------------------------------
//   Game_Actor
//--------------------------------
Game_Actor.prototype.getPets = function(){
	var pets = new Array();
	for(var i = 0; i < $gameParty.battlePets().length; i++){
		var pet = $gameParty.battlePets()[i];
		if(pet.master() === this)
			pets.push(pet);
	}

	return pets;
};

Game_Actor.prototype.orderPets = function(){
	var pets = this.getPets();
	for(var i = 0; i < pets.length; i++){
		var pet = pets[i];
		pet.setIndexForMaster(i + 1);
	}
};

Game_Actor.prototype.petsNum = function(){
	return this.getPets().length;
};

//---------------------------------
//   Game_Pet
//--------------------------------
function Game_Pet() {
    this.initialize.apply(this, arguments);
};

Game_Pet.prototype = Object.create(Game_Actor.prototype);
Game_Pet.prototype.constructor = Game_Pet;

Game_Pet.prototype.initialize = function(petId, enemyId){
	Game_Actor.prototype.initialize.call(this, enemyId);

	this._petId = petId;
	this._masterActorId = 0; //召喚主體
	this._indexForMaster = 0;//寵物序列號【與主體排序】
	this._inBattle = false; //是否出戰
	this._petDying = false;
	this._dieOpacity = 255;
	this._baseItem = null;//召喚物【道具/裝備/技能】
};

Game_Pet.prototype.setBaseItem = function(item){
	this._baseItem = item;
};

Game_Pet.prototype.baseItem = function(){
	return this._baseItem;
};

Game_Pet.prototype.isPet = function(){
	return true;
};

Game_Pet.prototype.isInBattle = function(){
	return !!this._inBattle;
};

Game_Pet.prototype.startDie = function(){
	this._petDying = true;
};

Game_Pet.prototype.endDie = function(){
	this._petDying = false;
};

Game_Pet.prototype.isPetDying = function(){
	return this._petDying;
};

Game_Pet.prototype.setDieOpacity = function(opacity){
	this._dieOpacity = opacity;
};

Game_Pet.prototype.dieOpacity = function(){
	return this._dieOpacity;
};

Game_Pet.prototype.master = function(){
	return $gameActors.actor(this._masterActorId);
};

Game_Pet.prototype.setMaster = function(masterId){
	this._masterActorId = masterId;
};

Game_Pet.prototype.setIndexForMaster = function(index){
	this._indexForMaster = index;
};

Game_Pet.prototype.indexForMaster = function(){
	return this._indexForMaster;
};

Game_Pet.prototype.canFight = function(){
	return $gameParty.canFightPet() && !this.isInBattle();
};

//出戰
Game_Pet.prototype.fight = function(){
	this._inBattle = true;
};

Game_Pet.prototype.canRest = function(){
	return this.isInBattle();
};

//休息
Game_Pet.prototype.rest = function(){
	this._inBattle = false;
};

Game_Pet.prototype.setup = function(enemyId){
    var pet = $dataEnemies[enemyId];
    this.initBaseData(pet);
    this.initImages();
    if(Imported.YEP_ClassChangeCore)
    	this.initClasses(); //初始化職業轉換，沒啥用，適配插件的
    
    this.initExp();
    this.initSkills();
    this.initEquips(pet.equips);
    this.clearParamPlus();

    if(Imported.CP_ClassExp){
    	this.initClassInfo();
		this.setHasClassLevelUp(false)
    }

    if(Imported.GT_EquipSuitCore)
    	this.refreshEquipSuit();

    this.recoverAll();
};

//讀取當前寵物對應的敵人數據
Game_Pet.prototype.getEnemyData = function(enemyId){
    return $dataEnemies[enemyId];
};

Game_Pet.prototype.initBaseData = function(pet){
    this._baseId = pet.id;
    this._name = pet.name;
    this._classId = pet.petClassId;
    this._level = pet.initLevel || 1;
};

Game_Pet.prototype.initClasses = function(){
	if(!this._unlockedClasses)
		this._unlockedClasses = [];
};

Game_Pet.prototype.isAutoBattle = function() {
    return Game_Actor.prototype.isAutoBattle.call(this) || this.pet().petAutoBattle;
};

Game_Pet.prototype.initImages = function(){
	Game_Actor.prototype.initImages.call(this);

	this._battlerName = this.pet().petBattlerName;
};

Game_Pet.prototype.pet = function(){
	return $dataEnemies[this._baseId];
};

Game_Pet.prototype.actor = function(){
	return this.pet();
};

Game_Pet.prototype.petId = function(){
	return this._petId;
};

Game_Pet.prototype.actorId = function(){
	return this.petId();
};

Game_Pet.prototype.paramBase = function(paramId) {
    var pet = this.pet();
    if(pet.classAffectParam)
    	return this.currentClass().params[paramId][this._level];
    else if(!!pet.customParamCode)
    	return this.customParam(paramId);
    else
    	return pet.params[paramId];
};

Game_Pet.prototype.customParam = function(paramId){
	var pet = this.pet();
	var base = {};
	base.mhp = pet.params[0];
	base.mmp  = pet.params[1];
	base.atk = pet.params[2];
	base.def = pet.params[3];
	base.mat = pet.params[4];
	base.mdf = pet.params[5];
	base.agi = pet.params[6];
	base.luk = pet.params[7];

	var level = this._level;
	var mhp = base.mhp;
	var mmp = base.mmp;
	var atk = base.atk;
	var def = base.def;
	var mat = base.mat;
	var mdf = base.mdf;
	var agi = base.agi;
	var luk = base.luk;

	try{
		eval(pet.customParamCode);

		switch(paramId){
			case 0:
				return mhp;
			case 1:
				return mmp;
			case 2:
				return atk;
			case 3:
				return def;
			case 4:
				return mat;
			case 5:
				return mdf;
			case 6:
				return agi;
			case 7:
				return luk;
			default:
				return 0;
		}
	}catch(err){
		console.error(err);
		return 0;
	}
};

Game_Pet.prototype.maxLevel = function(){
	return this.pet().petMaxLevel;
};

//死亡額外代碼
Game_Pet.prototype.die = function(){
	Game_Actor.prototype.die.call(this);

	this.setDieOpacity(this.battler().opacity);
	this.startDie();
};

Game_Pet.prototype.initSkills = function() {
    this._skills = [];
    var skillList = this.pet().actions;

    skillList.forEach(function(action){
    	if(action.skillId > 1)
    		this.learnSkill(action.skillId);
    }, this);
};

Game_Pet.prototype.skills = function(){
	var skills = Game_Actor.prototype.skills.call(this);

	if(Imported.YEP_BattleAICore && this.isAutoBattle())
		skills = AIManager.getPatternSkills(skills, this.pet().petAiPattern);

	return skills;
};

//技能類型：寵物學習了這個類型的技能，他就有這個類型
Game_Pet.prototype.addedSkillTypes = function(){
    var types = Game_Actor.prototype.addedSkillTypes.call(this);
    this._skills.forEach((skillId) => {
        var skill = $dataSkills[skillId];
        if(!!skill && skill.stypeId > 0 && !types.contains(skill.stypeId))
            types.push(skill.stypeId);
    });
    return types;
};

//AI
Game_Pet.prototype.meetsCondition = function(action) {
    var param1 = action.conditionParam1;
    var param2 = action.conditionParam2;
    switch (action.conditionType) {
    case 1:
        return this.meetsTurnCondition(param1, param2);
    case 2:
        return this.meetsHpCondition(param1, param2);
    case 3:
        return this.meetsMpCondition(param1, param2);
    case 4:
        return this.meetsStateCondition(param1);
    case 5:
        return this.meetsPartyLevelCondition(param1);
    case 6:
        return this.meetsSwitchCondition(param1);
    default:
        return true;
    }
};

Game_Pet.prototype.meetsTurnCondition = function(param1, param2) {
    var n = $gameTroop.turnCount();
    if (param2 === 0) {
        return n === param1;
    } else {
        return n > 0 && n >= param1 && n % param2 === param1 % param2;
    }
};

Game_Pet.prototype.meetsHpCondition = function(param1, param2) {
    return this.hpRate() >= param1 && this.hpRate() <= param2;
};

Game_Pet.prototype.meetsMpCondition = function(param1, param2) {
    return this.mpRate() >= param1 && this.mpRate() <= param2;
};

Game_Pet.prototype.meetsStateCondition = function(param) {
    return this.isStateAffected(param);
};

Game_Pet.prototype.meetsPartyLevelCondition = function(param) {
    return $gameParty.highestLevel() >= param;
};

Game_Pet.prototype.meetsSwitchCondition = function(param) {
    return $gameSwitches.value(param);
};

Game_Pet.prototype.isActionValid = function(action) {
    return this.meetsCondition(action) && this.canUse($dataSkills[action.skillId]);
};

Game_Pet.prototype.makeAutoBattleActions = function(){
	if(this.isConfused()){
  		this.makeConfusionActions();
 	}else if (Imported.YEP_BattleAICore && this.pet().petAiPattern.length > 0) {
   		this.setAIPattern();
		this.setActionState('waiting');
 	}else {
    	this.makeDefaultAutoActions();
    }
};

Game_Pet.prototype.selectAllActions = function(actionList) {
    var ratingMax = Math.max.apply(null, actionList.map(function(a) {
        return a.rating;
    }));
    var ratingZero = ratingMax - 3;
    actionList = actionList.filter(function(a) {
        return a.rating > ratingZero;
    });
    for (var i = 0; i < this.numActions(); i++) {
        this.action(i).setEnemyAction(this.selectAction(actionList, ratingZero));
    }
};

Game_Pet.prototype.makeDefaultAutoActions = function(){
    if(this.numActions() > 0){
        var actionList = this.pet().actions.filter(function(a){
            return this.isActionValid(a);
        }, this);
        if (actionList.length > 0){
            this.selectAllActions(actionList);
        }
    }
    this.setActionState('waiting');
};

Game_Pet.prototype.selectAction = function(actionList, ratingZero) {
    var sum = actionList.reduce(function(r, a) {
        return r + a.rating - ratingZero;
    }, 0);
    if (sum > 0) {
        var value = Math.randomInt(sum);
        for (var i = 0; i < actionList.length; i++) {
            var action = actionList[i];
            value -= action.rating - ratingZero;
            if (value < 0) {
                return action;
            }
        }
    } else {
        return null;
    }
};

if(Imported.YEP_BattleAICore){

Game_Pet.prototype.setAIPattern = function(){
    Game_Battler.prototype.setAIPattern.call(this);

    if (this.numActions() <= 0) return;
    AIManager.setBattler(this);
    for(var i = 0; i < this.pet().petAiPattern.length; ++i){
    	if(Math.random() > this.aiLevel()) continue;
    	var line =  this.pet().petAiPattern[i];
    	if(AIManager.isDecidedActionAI(line)) return;
    }

    this.makeDefaultAutoActions();
};

Game_Pet.prototype.aiLevel = function(){
	return this.pet().petAiLevel;
};

}

if(Imported.GT_EquipSuitCore){

Game_Pet.prototype.getEquipSuitBonusesIDs = function(){
	if(!this._equipSuits || !this._equipSuitsTotal)
		this.refreshEquipSuit();
	Game_Actor.prototype.getEquipSuitBonusesIDs.call(this);
};

}

//--------------------------------
// Game_Party
//---------------------------------
CP.PetManager.INIT_ALL_PARTY_ITEMS = Game_Party.prototype.initAllItems;
Game_Party.prototype.initAllItems = function() {
    CP.PetManager.INIT_ALL_PARTY_ITEMS.call(this);

    this._pets = [];//寵物
    this._petsDepository = [];//寵物倉庫
    this._changingPet = false;
};

Game_Party.prototype.startChangePet = function(){
	this._changingPet = true;
};

Game_Party.prototype.finishChangePet = function(){
	this._changingPet = false;
};

Game_Party.prototype.isChangingPet = function(){
	return !!this._changingPet;
};

Game_Party.prototype.pets = function(){
	return this._pets.map(function(petId){
		return $gameActors.actor(petId);
	});
};

Game_Party.prototype.petsDepository = function(){
	return this._petsDepository.map(function(petId){
		return $gameActors.actor(petId);
	});
};

Game_Party.prototype.clearPets = function(){
	var pets = JSON.parse(JSON.stringify(this._pets));
	pets.forEach(function(petId){
		this.releasePet(petId);
	}, this);
};

Game_Party.prototype.clearAllPets = function(){
	this._pets = this._pets.concat(this._petsDepository);
	this.clearPets();
};

Game_Party.prototype.battlePets = function(){
	return this.pets().filter(function(pet){
		return pet.isInBattle();
	});
};

Game_Party.prototype.aliveBattleActors = function(){
	return this.battleMembersNotPets().filter(function(actor){
		return actor.isAlive();
	});
};

Game_Party.prototype.maxPets = function(){
	return CP.PetManager.MAX_PETS_NUMBER;
};

Game_Party.prototype.maxBattlePets = function(){
	return CP.PetManager.MAX_BATTLE_PETS_NUMBER;
};

Game_Party.prototype.maxBattlers = function(){
	return this.maxBattleMembers() + this.maxBattlePets();
};

Game_Party.prototype.canAddPet = function(){
	var length = this.maxPets();
	if(this.isChangingPet())
		length++;
	return this._pets.length < length;
};

Game_Party.prototype.canAddFightPet = function(){
	var length = this.maxBattlePets();
	if(this.isChangingPet())
		length++;
	return this.battlePets().length < length;
};

Game_Party.prototype.canFightPet = function(){
	return this.battlePets().length < this.maxBattlePets();
};

Game_Party.prototype.addPet = function(enemyId, masterId){
	if(!this.canAddPet())
		return -1;

	var petId = $gameActors.addPet(enemyId);
	this.setMasterForPet(petId, masterId);
	this._pets.push(petId);

	this.onPetAdded(petId);

	return petId;
};

Game_Party.prototype.setMasterForPet = function(petId, masterId){
	var pet = $gameActors.actor(petId);
	var master = $gameActors.actor(masterId);
	pet.setMaster(masterId);

	var masterPets = master.getPets();
	if(!masterPets.contains(pet))
		pet.setIndexForMaster(masterPets.length + 1);
};

Game_Party.prototype.onPetAdded = function(petId){
	var pet = $gameActors.actor(petId);

	try{
		eval(pet.pet().petAddedCode);
	}catch(err){
		console.error(err);
	}
};

//移除寵物包括兩種操作，存倉庫和放生
Game_Party.prototype.removePet = function(petId){
	var index = this._pets.indexOf(petId);
	if(index >= 0){
		this._pets.splice(index, 1);
		return true;
	}

	return false;
};

//放生
Game_Party.prototype.releasePet = function(petId){
	if(this.removePet(petId))
		$gameActors.deletePet(petId);
};

//交換
Game_Party.prototype.changePet = function(petId1, petId2, needDepository){
	var pet1 = $gameActors.actor(petId1);
	var pet2 = $gameActors.actor(petId2);

	if(!pet1 || !pet2)  return false;
	if(!pet1.isInBattle() || pet2.isInBattle())  return false;

	var masterId = pet1.master().actorId();
	pet1.rest();
	pet2.setMaster(masterId);
	pet2.setIndexForMaster(pet1.indexForMaster());
	pet2.fight();

	if(needDepository)
		$gameParty.addPetsDepository(petId1);

	this.onPetChanged(pet1, pet2);

	return true;
};

Game_Party.prototype.onPetChanged = function(oldPet, newPet){
	var oldItem = oldPet.baseItem();
	var newItem = newPet.baseItem();
	try{
		eval(CP.PetManager.PET_CHANGE_CODE);
	}catch(err){
		console.error(err);
	}
};

//放倉庫
Game_Party.prototype.addPetsDepository = function(petId){
	if(this.removePet(petId)){
		this._petsDepository.push(petId);

		$gameActors.actor(petId).rest();
	}
};

//取倉庫
Game_Party.prototype.getPetFromDepository = function(petId){
	var index = this._petsDepository.indexOf(petId);
	if(index >= 0){
		this._petsDepository.splice(index, 1);
		this._pets.push(petId);
	}
};

CP.PetManager.PARTY_ALL_MEMBERS = Game_Party.prototype.allMembers;
Game_Party.prototype.allMembers = function(){
    return CP.PetManager.PARTY_ALL_MEMBERS.call(this).concat(this.battlePets());
};

CP.PetManager.PARTY_BATTLE_MEMBERS = Game_Party.prototype.battleMembers;
Game_Party.prototype.battleMembers = function(){
	var data = CP.PetManager.PARTY_BATTLE_MEMBERS.call(this).concat(this.battlePets());
	var result = [];
	data.forEach(function(actor){
		if(!result.contains(actor))
			result.push(actor);
	});

	return result;
};

Game_Party.prototype.battleMembersNotPets = function(){
	return this.battleMembers().filter(function(member){
		return !member.isPet();
	});
};

Game_Party.prototype.petsDepository = function(){
	return this._petsDepository.map(function(petId){
		return $gameActors.actor(petId);
	});
};

Game_Party.prototype.onBattleEnd = function(){
	Game_Unit.prototype.onBattleEnd.call(this);

	this.onBattleEndPetEffect();
};

Game_Party.prototype.onBattleEndPetEffect = function(){
	try{
		eval(CP.PetManager.BATTLE_ENDED_CODE);
	}catch(err){
		console.error(err);
	}
};

CP.PetManager.PARTY_ALL_DEAD = Game_Party.prototype.isAllDead;
Game_Party.prototype.isAllDead = function() {
    if(CP.PetManager.PARTY_ALL_DEAD.call(this))
    	return true;

    if($gameSystem.defeatWhenOnlyPetsAlive() && this.aliveBattleActors().length === 0)
    	return true;

    return false;
};

Game_Party.prototype.minPetsActor = function(){
	var members = this.battleMembersNotPets();
	var result = members[0];
	for(var i = 0; i < members.length; i++){
		if(members[i] && members[i].petsNum() < result.petsNum())
			result = members[i];
	}

	return result;
};

Game_Party.prototype.resetPetMaster = function(pet){
	var master = this.minPetsActor();
	this.setMasterForPet(pet.petId(), master.actorId());
};

Game_Party.prototype.resetAllPetsOrder = function(){
	this.battlePets().forEach(function(pet){
		this.resetPetMaster(pet)
	}, this);
};

//--------------------------------
// Game_Action
//---------------------------------
CP.PetManager.INIT_BATTLE_ACTION = Game_Action.prototype.initialize;
Game_Action.prototype.initialize = function(subject, forcing){
    CP.PetManager.INIT_BATTLE_ACTION.call(this, subject, forcing);

    this.setChangePetId(0);
};

Game_Action.prototype.setChangePetId = function(id){
	this._changePetId = id;
};

Game_Action.prototype.petNeedChange = function(){
	return $gameActors.actor(this._changePetId);
};

Game_Action.prototype.canChangePet = function(){
	return this._changePetId > 0;
};

Game_Action.prototype.isAddPetAction = function(){
	return CP.PetManager.isAddPetItem(this.item());
};

CP.PetManager.MAKE_ACTION_TARGETS = Game_Action.prototype.makeTargets;
Game_Action.prototype.makeTargets = function(){
	if(this.isAddPetAction())
		$gameParty.startChangePet();
	if(this.isAddPetAction() && $gameParty.canAddFightPet()){
		return this.createOrChangePet(this.item().petAddedInfo.enemyId);
	}
	else
		return CP.PetManager.MAKE_ACTION_TARGETS.call(this);
};

Game_Action.prototype.createOrChangePet = function(enemyId){
	var result = [];
	if(this.canChangePet()){
		result = this.changeNewPet(enemyId);
		this.setChangePetId(0);
	}else
		result = this.createPet(enemyId);

	return result;
};

Game_Action.prototype.createPet = function(enemyId){
	var result = [];
	var pet = null;
	
	var petId = $gameParty.addPet(enemyId, this.subject().actorId());
	pet = $gameActors.actor(petId);

	if(pet){
		var item = this.item();
		if(Imported.CP_UseEquip && this.equipItem())
			item = this.equipItem();
		pet.setBaseItem(item);
		pet.fight();
		result.push(pet);
	}

	return result;
};

Game_Action.prototype.changeNewPet = function(enemyId){
	var result = [];
	var pet = null;
	
	var petId = $gameParty.addPet(enemyId, this.subject().actorId());
	pet = $gameActors.actor(petId);

	if(pet){
		var item = this.item();
		if(Imported.CP_UseEquip && this.equipItem())
			item = this.equipItem();
		pet.setBaseItem(item);
		result.push(pet);
		$gameParty.changePet(this.petNeedChange().petId(), petId);
	}

	$gameParty.finishChangePet();

	return result;
};

CP.PetManager.APPLY_ACTION = Game_Action.prototype.apply;
Game_Action.prototype.apply = function(target){
	CP.PetManager.APPLY_ACTION.call(this, target);

	$gameParty.finishChangePet();
};

//--------------------------------
// Game_System
//---------------------------------
CP.PetManager.INIT_SYS = Game_System.prototype.initialize;
Game_System.prototype.initialize = function(){
	CP.PetManager.INIT_SYS.call(this);

	this._defeatWhenOnlyPetsAlive = CP.PetManager.DEFEAT_WHEN_ONLY_PETS_ALIVE;
};

Game_System.prototype.defeatWhenOnlyPetsAlive = function(){
	return !!this._defeatWhenOnlyPetsAlive;
};

Game_System.prototype.setDefeatWhenOnlyPetsAlive = function(defeat){
	this._defeatWhenOnlyPetsAlive = defeat;
};

//--------------------------------
// Game_Interpreter
//---------------------------------
CP.PetManager.PLUGIN_COMMAND = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args){
    CP.PetManager.PLUGIN_COMMAND.call(this, command, args);

    if(command == 'AddPet'){
    	var enemyId = Number(args[0]) || 0;
    	var master = Number(args[1]) || 0;
    	var autoFight = false;
    	if(args[2] && args[2] == "autoFight")
    		autoFight = true;

    	if(enemyId > 0){
    		if(master <= 0)
    			 master = $gameParty.leader().actorId();
    		var petId = $gameParty.addPet(enemyId, master);
    		if(petId > 0){
    			var pet = $gameActors.actor(petId);
    			if(autoFight)
    				pet.fight();
    		}
    	}
    }

    if(command == 'ShowPetScene')
    	SceneManager.push(Scene_Pet);
};

//--------------------------------
// Spriteset_Battle
//---------------------------------
CP.PetManager.CREATE_BATTLE_ACTOR_SPRITES = Spriteset_Battle.prototype.createActors;
Spriteset_Battle.prototype.createActors = function(){
	CP.PetManager.CREATE_BATTLE_ACTOR_SPRITES.call(this);
	this.createPets();
};

Spriteset_Battle.prototype.createPets = function(){
	this._petSprites = [];
	for(var i = 0; i < $gameParty.maxBattlePets(); i++){
		this._petSprites[i] = new Sprite_Pet();
		this._battleField.addChild(this._petSprites[i]);
	}
};

CP.PetManager.SPRITESET_BATTLER_SPRITES = Spriteset_Battle.prototype.battlerSprites;
Spriteset_Battle.prototype.battlerSprites = function() {
    return CP.PetManager.SPRITESET_BATTLER_SPRITES.call(this).concat(this._petSprites);
};

Spriteset_Battle.prototype.getMasterSprite = function(battler){
	for(var i = 0; i < this._actorSprites.length; i++){
		var sprite = this._actorSprites[i];
		var master = battler.master();
		if(sprite._actor === master)
			return sprite;
	}

	return null;
};

Spriteset_Battle.prototype.updateActors = function(){
	this.updateMasterActors();
	this.updatePets();
};

Spriteset_Battle.prototype.updateMasterActors = function() {
    var members = $gameParty.battleMembersNotPets();
    for (var i = 0; i < this._actorSprites.length; i++)
        this._actorSprites[i].setBattler(members[i]);
};

Spriteset_Battle.prototype.updatePets = function(){
	var members = $gameParty.battlePets();
	for(var i = 0; i < $gameParty.maxBattlePets(); i++){
		var pet = members[i];
		if(!!pet)
			this._petSprites[i].setBattler(pet);
		else
			this._petSprites[i].setBattler(null);
	}
};

//--------------------------------
// Sprite_Battler
//---------------------------------
Sprite_Battler.prototype.isPetSprite = function() {
    return false;
};

CP.PetManager.SET_BATTLER_SPRITE = Sprite_Battler.prototype.setBattler;
Sprite_Battler.prototype.setBattler = function(battler){
	CP.PetManager.SET_BATTLER_SPRITE.call(this, battler);

	if(!Imported.YEP_BattleEngineCore && battler)
		battler.setBattler(this);
};

//--------------------------------
// Sprite_Pet
//---------------------------------
function Sprite_Pet(){
	this.initialize.apply(this, arguments);
};

Sprite_Pet.prototype = Object.create(Sprite_Actor.prototype);
Sprite_Pet.prototype.constructor = Sprite_Pet;

Sprite_Pet.prototype.initialize = function(){
	Sprite_Actor.prototype.initialize.apply(this, arguments);
};

Sprite_Pet.prototype.masterSprite = function(){
	return this._actor.master().battler();
};

Sprite_Pet.prototype.isPetSprite = function() {
    return true;
};

Sprite_Pet.prototype.setBattler = function(battler){
	var changed = battler !== this._actor;
	Sprite_Actor.prototype.setBattler.call(this, battler);

	if(changed)
		this.createDragonbones(); //有龍骨數據執行創建龍骨
};

//龍骨插件專用
Sprite_Pet.prototype.createDragonbones = function(){
	//存在數據即移除
	if(!!this._dragonbone)
		this.removeChild(this._dragonbone);//當角色替換時無條件移除龍骨，不管他是不是null
	if(!this._actor)
		return; 

	var dataPet = this._actor.pet();
	var i = this._actor.actorId();
	var tempArmatureName = dataPet.meta.dragonbone;
	
	if(tempArmatureName){
		//定義scale
		var tempScaleX = -dataPet.meta.dragonbone_scalex;
		var tempScaleY = dataPet.meta.dragonbone_scaley;

		//Delete last battle armature
		if (dragonBonesIntegration.ArmatureDatabaseActor[i]){
			dragonBonesIntegration.ArmatureDatabaseActor[i].dispose();
		}

		//create new armature
		dragonBonesIntegration.ArmatureDatabaseActor[i] = 
			dragonBonesIntegration.CreateArmature(tempArmatureName, 0, 0);
		
		//initialize dragon data inside the game actor in order to handle 
		//animation state changes
		if(dragonBonesIntegration.ArmatureDatabaseActor[i]){
			//tell whether a battler has a dragonbone armature
			this._actor.hasDragonBone = true;
			this._actor.dragonboneIndex = i;
			this._actor.dragonboneAnimation = [];

			//transition to idle when animation finish playing.  This should stop 
			//most animation hitches.
			this._actor.AutoTransitionToIdle = function(event){
				switch (event.type) {
					case dragonBones.EventObject.COMPLETE:
						//if actor is not knocked out
						if(this._states.contains(1) === false){
							//var idleAnimation = this.dragonboneAnimation['walk'];
							//dragonBonesIntegration.ArmatureDatabaseActor
							//[this.dragonboneIndex].animation.play(idleAnimation); 
							this.lastMotionType = null;
							dragonBonesIntegration.PlayAnimationOnBattler(this, "walk");
						}
						break;
					default:
					//nothing
				}                                           
			}

			//Automatically transition to idle when animation is complete by using
			//Event
			var actorData = dragonBonesIntegration.ArmatureDatabaseActor[i];
			actorData.addEvent(dragonBones.EventObject.COMPLETE,
				this._actor.AutoTransitionToIdle, this._actor);

			//parse meta data into animation
			for (var key in dataPet.meta){
				if(dataPet.meta.hasOwnProperty(key)) {
					var animationIndex = key.split("dragonbone_ani_");
					if(animationIndex[1]){
						this._actor.dragonboneAnimation[animationIndex[1]] = dataPet.meta[key];
					}
					//console.log('Key = ' + key +  ' :: ' +  animationIndex + " = " +
					//dataPet.meta[key]);
					//console.log(key + " -> " + dataPet.meta[key]);
				}
			}

			//set scale
			if (tempScaleX){
				dragonBonesIntegration.ArmatureDatabaseActor[i].scale.x = tempScaleX;
			}
			if (tempScaleY){
				dragonBonesIntegration.ArmatureDatabaseActor[i].scale.y = tempScaleY;
			}
			this._dragonbone = dragonBonesIntegration.ArmatureDatabaseActor[i];
			this.addChild(this._dragonbone);
		}
	}                  
};

Sprite_Pet.prototype.setActorHome = function(index){
    var initIndex = index;
	var index = this._actor.indexForMaster();
	var pet = this._actor.pet();
	var x = 0;
	var y = 0;

	if(pet.defaultPetPosition)
		Sprite_Actor.prototype.setActorHome.call(this, initIndex);
	else{
		try{
			var master = this.masterSprite();
			eval(pet.homePosition);
			if(!Imported.YEP_BattleEngineCore && $gameTroop.turnCount() === 0)
				x -= 300;

			this.setHome(x, y);
			this.moveToStartPosition();
		}catch(err){
			console.error(err);
			Sprite_Actor.prototype.setActorHome.call(this, initIndex);
		}
	}
};

Sprite_Pet.prototype.update = function(){
	Sprite_Actor.prototype.update.call(this);

	if(this._actor && this._actor.isPetDying())
		this.updatePetOpacity();
};

Sprite_Pet.prototype.updatePetOpacity = function(){
	var opacity = this._actor.dieOpacity();
	var speed = Math.round(opacity / this._actor.pet().petExitTime);
	if(speed < 1)
		speed = 1;

	if(speed === Infinity){
		this.onExitEnd();
		this._actor.endDie();
		return;
	}

	this.opacity -= speed;
	if(this.opacity <= 0){
		this.onExitEnd();
		this._actor.endDie();
	}
};

Sprite_Pet.prototype.onExitEnd = function(){
	var pet = this._actor;
	try{
		if(pet)
			eval(pet.pet().petDieCode);
	}catch(err){
		console.error(err);
	}
};

//--------------------------------
// Window_PetList
//---------------------------------
function Window_PetList(){
	this.initialize.apply(this, arguments);
};

Window_PetList.prototype = Object.create(Window_Selectable.prototype);
Window_PetList.prototype.constructor = Window_PetList;

Window_PetList.prototype.initialize = function(x, y, height){
	var width = this.windowWidth();

	Window_Selectable.prototype.initialize.call(this, x, y, width, height);
	this.deselect();
	this.deactivate();
};

Window_PetList.prototype.windowWidth = function(){
	return eval(CP.PetManager.TYPE_WINDOW_WIDTH);
};

Window_PetList.prototype.maxItems = function(){
	return !!this._list ? this._list.length : 0;
};

Window_PetList.prototype.refreshPetList = function(){
	if(!this._list)
		this._list = [];

	switch(this.parent.parent.typeIndex()){
		case 0:
			this._list = $gameParty.pets();
			break;
		case 1:
			this._list = $gameParty.petsDepository();
			break;
	}
};

Window_PetList.prototype.setSelectCallback = function(callback){
	this._selectCallback = callback;
};

Window_PetList.prototype.refresh = function(){
	this.refreshPetList();

	Window_Selectable.prototype.refresh.call(this);
};

Window_PetList.prototype.currentPet = function(){
	if(!this._list)
		return null;
	return this._list[this.index()];
};

Window_PetList.prototype.drawItem = function(index){
	var pet = this._list[index];
	var rect = this.itemRect(index);

	this.resetTextColor();
	if(pet.isInBattle())
		this.changeTextColor(this.fightColor());
	this.drawText(pet.name(), rect.x, rect.y, rect.width / 2, "left");

	if(this.canShowPetLevel())
		this.drawText(CP.PetManager.PET_LEVEL_NAME + pet.level, rect.x + rect.width / 2, rect.y
            , rect.width / 2, "right");
};

Window_PetList.prototype.canShowPetLevel = function(){
    return CP.PetManager.SHOW_PET_LEVEL;
};

Window_PetList.prototype.select = function(index){
	Window_Selectable.prototype.select.call(this, index);

	if(this._selectCallback)
		this._selectCallback.call(this);
};

Window_PetList.prototype.fightColor = function(){
	return this.textColor(CP.PetManager.PET_LIST_BATTLE_COLOR);
};

if(CP.PetManager.USE_SCENE){

//--------------------------------
// Window_MenuCommand
//---------------------------------
CP.PetManager.ADD_MENU_ORIGINAL_COMMANDS = Window_MenuCommand.prototype.addOriginalCommands;
Window_MenuCommand.prototype.addOriginalCommands = function(){
	CP.PetManager.ADD_MENU_ORIGINAL_COMMANDS.call(this);

	this.addPetCommand();
};

Window_MenuCommand.prototype.addPetCommand = function(){
	this.addCommand(CP.PetManager.PET_COMMAND_NAME, "pet");
};

//--------------------------------
// Scene_Menu
//---------------------------------
CP.PetManager.CREATE_SCENE_COMMAND_WINDOW = Scene_Menu.prototype.createCommandWindow;
Scene_Menu.prototype.createCommandWindow = function(){
	CP.PetManager.CREATE_SCENE_COMMAND_WINDOW.call(this);

	this._commandWindow.setHandler("pet", this.onPetCommand.bind(this));
};

Scene_Menu.prototype.onPetCommand = function(){
	SceneManager.push(Scene_Pet);
};

//--------------------------------
// Scene_Pet
//---------------------------------
function Scene_Pet(){
	this.initialize.apply(this, arguments);
};

Scene_Pet.prototype = Object.create(Scene_MenuBase.prototype);
Scene_Pet.prototype.constructor = Scene_Pet;

Scene_Pet.prototype.initialize = function(){
	Scene_MenuBase.prototype.initialize.call(this);

	this.setPet(0);
};

Scene_Pet.prototype.setPet = function(petId){
	this._petId = petId;
};

Scene_Pet.prototype.pet = function(){
	return $gameActors.actor(this._petId);
};

Scene_Pet.prototype.create = function(){
	Scene_MenuBase.prototype.create.call(this);

	this.createHelpWindow();
	this.createTypeWindow();
	this.createListWindow();
	this.createCommandWindow();
	this.createStatusWindow();
	this.createDetailWindow();
	this.createConfirmWindow();
	this.reserveFaceImages();
};

Scene_Pet.prototype.createHelpWindow = function(){
	Scene_MenuBase.prototype.createHelpWindow.call(this);

	this.resetHelpText();
};

Scene_Pet.prototype.createTypeWindow = function(){
	var y = this._helpWindow.height;
	this._typeWindow = new Window_PetTypeSelect(0, y);

	this._typeWindow.setHandler("cancel", this.popScene.bind(this));
	this._typeWindow.setHandler("ok", this.onTypeOk.bind(this));

	this.addWindow(this._typeWindow);
};

Scene_Pet.prototype.typeIndex = function(){
	return this._typeWindow.index();
};

Scene_Pet.prototype.createListWindow = function(){
	var y = this._typeWindow.y + this._typeWindow.height;
	var height = Graphics.boxHeight - y;
	this._listWindow = new Window_PetList(0, y, height);

	this._listWindow.setHandler("cancel", this.onListCancel.bind(this));
	this._listWindow.setHandler("ok", this.onListOk.bind(this));
	this._listWindow.setSelectCallback(this.onListSelect.bind(this));

	this.addWindow(this._listWindow);
	this._listWindow.refresh();
};

Scene_Pet.prototype.createStatusWindow = function(){
	var x = this._typeWindow.width;
	var y = this._helpWindow.height;
	var width = Graphics.boxWidth - x;
	var height = eval(CP.PetManager.STATUS_WINDOW_HEIGHT);

	this._statusWindow = new Window_PetStatus(x, y, width, height);
	this.addWindow(this._statusWindow);
};

Scene_Pet.prototype.createDetailWindow = function(){
	var x = this._listWindow.width + this._listWindow.x;
	var y = this._statusWindow.y + this._statusWindow.height;
	var width = Graphics.boxWidth - x;
	var height = this._commandWindow.y - y;

	this._detailWindow = new Window_PetDetail(x, y, width, height);
	this.addWindow(this._detailWindow);
};

Scene_Pet.prototype.createCommandWindow = function(){
	var x = this._listWindow.x + this._listWindow.width;
	var height = Window_Base.prototype.lineHeight() * 2 + CP.PetManager.COMMAND_WINDOW_HEIGHT_PLUS;
	var width = Graphics.boxWidth - x;
	var y = Graphics.boxHeight - height;
	this._commandWindow = new Window_PetCommand(x, y, width, height);

	this._commandWindow.setHandler("cancel", this.onCommandCancel.bind(this));
	this._commandWindow.setHandler("fight", this.onCommandFight.bind(this));
	this._commandWindow.setHandler("rest", this.onCommandRest.bind(this));
	this._commandWindow.setHandler("depository", this.onCommandDepository.bind(this));
	this._commandWindow.setHandler("release", this.onCommandRelease.bind(this));

	this.addWindow(this._commandWindow);
};

Scene_Pet.prototype.createConfirmWindow = function(){
	var y = Math.round(Graphics.boxHeight / 2 - Window_Base.prototype.standardPadding() * 2) + CP.PetManager.RELEASE_CONFIRM_Y_OFFSET;

	this._confirmWindow = new Window_ReleaseConfirm(0, y);
	var x = Math.round(Graphics.boxWidth / 2 - this._confirmWindow.textWidth(CP.PetManager.RELEASE_CONFIRM_INFO) / 2) 
		+ CP.PetManager.RELEASE_CONFIRM_X_OFFSET;
	this._confirmWindow.x = x;
	this._confirmWindow.setHandler("ok", this.onConfirmOk.bind(this));
	this._confirmWindow.setHandler("cancel", this.onConfirmCancel.bind(this));

	this.addWindow(this._confirmWindow);
};

Scene_Pet.prototype.onTypeOk = function(){
	this._typeWindow.deactivate();
	this._listWindow.activate();
	this._listWindow.select(0);
};

Scene_Pet.prototype.onListCancel = function(){
	this._listWindow.deselect();
	this._listWindow.deactivate();
	this._typeWindow.activate();
};

Scene_Pet.prototype.onListSelect = function(){
	var pet = this._listWindow.currentPet();
	if(pet)
		this.setPet(pet.petId());
	else
		this.setPet(0);

	this._statusWindow.refresh();

	this._commandWindow.setPet(this._petId);
	this._detailWindow.setPet(this._petId);
	this._commandWindow.refresh();
	this._detailWindow.refresh();
};

Scene_Pet.prototype.onListOk = function(){
	this._listWindow.deactivate();
	
	this._commandWindow.activate();
	this._commandWindow.select(0);
};

Scene_Pet.prototype.goToListFromCommand = function(){
	this._listWindow.activate();
	this._listWindow.refresh();
	this._commandWindow.deselect();
	this._commandWindow.deactivate();

	this._statusWindow.refresh();
	this._detailWindow.refresh();
};

Scene_Pet.prototype.onCommandFight = function(){
	this.pet().fight();

	if(CP.PetManager.RESET_ALL_PETS_MASTER)
		$gameParty.resetAllPetsOrder();

	this.goToListFromCommand();
	this.setHelpText(CP.PetManager.FIGHT_HELP_TEXT.format(this.pet().name()));
};

Scene_Pet.prototype.onCommandRest = function(){
	this.pet().rest();

	this.goToListFromCommand();
	this.setHelpText(CP.PetManager.REST_HELP_TEXT.format(this.pet().name()));
};

Scene_Pet.prototype.onCommandDepository = function(){
	var petId = this.pet().petId();
	var name = this.pet().name();

	if(this.typeIndex() === 1){
		$gameParty.getPetFromDepository(petId);
		this.setHelpText(CP.PetManager.DEPOSITORY_OUT_HELP_TEXT.format(name));
	}
	else{
		$gameParty.addPetsDepository(petId);
		this.setHelpText(CP.PetManager.DEPOSITORY_IN_HELP_TEXT.format(name));
	}

	this.goToListFromCommand();
};

Scene_Pet.prototype.onCommandRelease = function(){
	this._commandWindow.deactivate();
	this._confirmWindow.setPet(this.pet().petId());
	this._confirmWindow.show();
	this._confirmWindow.open();
	this._confirmWindow.refresh();
	this._confirmWindow.select(0);
	this._confirmWindow.activate();
};

Scene_Pet.prototype.onCommandCancel = function(){
	this._commandWindow.deselect();
	this._commandWindow.deactivate();
	this._listWindow.activate();
};

Scene_Pet.prototype.onConfirmOk = function(){
	var pet = this.pet();
	if(pet){
		$gameParty.releasePet(pet.petId());
		this.setHelpText(CP.PetManager.RELEASE_HELP_TEXT.format(pet.name()));
	}

	this._confirmWindow.deselect();
	this._confirmWindow.deactivate();
	this._confirmWindow.close();
	this._listWindow.refresh();
	this._listWindow.activate();
	this._listWindow.reselect();
};

Scene_Pet.prototype.onConfirmCancel = function(){
	this._confirmWindow.deselect();
	this._confirmWindow.deactivate();
	this._confirmWindow.close();
	this._commandWindow.activate();
};

Scene_Pet.prototype.setHelpText = function(text){
	this._helpWindow.setText(text);
};

Scene_Pet.prototype.resetHelpText = function(){
	this.setHelpText(CP.PetManager.HELP_WINDOW_TEXT);
};

Scene_Pet.prototype.refreshPetList = function(){
	this._listWindow.refresh();
};

Scene_Pet.prototype.refreshCommandList = function(){
	this._commandWindow.refresh();
};

Scene_Pet.prototype.reserveFaceImages = function(){
   var pets = $gameParty.pets().concat($gameParty.petsDepository());
   pets.forEach(function(pet){
   		if(pet)
        	ImageManager.reserveFace(pet.faceName());
    });
};

//--------------------------------
// Window_PetTypeSelect
//---------------------------------
function Window_PetTypeSelect(){
	this.initialize.apply(this, arguments);
};

Window_PetTypeSelect.prototype = Object.create(Window_Selectable.prototype);
Window_PetTypeSelect.prototype.constructor = Window_PetTypeSelect;

Window_PetTypeSelect.prototype.initialize = function(x, y){
	var width = this.windowWidth();
	var height = this.windowHeight();

	Window_Selectable.prototype.initialize.call(this, x, y, width, height);
	this.refresh();
	this.activate();
	this.select(0);
};

Window_PetTypeSelect.prototype.maxItems = function(){
	return 2;
};

Window_PetTypeSelect.prototype.windowHeight = function(){
	return (this.maxRows() + 1) * this.itemHeight() + CP.PetManager.TYPE_WINDOW_HEIGHT_PLUS;
};

Window_PetTypeSelect.prototype.windowWidth = function(){
	return eval(CP.PetManager.TYPE_WINDOW_WIDTH);
};

Window_PetTypeSelect.prototype.drawItem = function(index){
	var name = CP.PetManager.PET_LIST_NAMES[index];
	var rect = this.itemRect(index);
	this.drawText(name, rect.x, rect.y, rect.width, "left");
};

Window_PetTypeSelect.prototype.select = function(index){
	Window_Selectable.prototype.select.call(this, index);

	if(this.parent && this.parent.parent){
		this.parent.parent.refreshPetList();
		this.parent.parent.refreshCommandList();
	}
};

//--------------------------------
// Window_PetStatus
//---------------------------------
function Window_PetStatus(){
	this.initialize.apply(this, arguments);
};

Window_PetStatus.prototype = Object.create(Window_Base.prototype);
Window_PetStatus.prototype.constructor = Window_PetStatus;

Window_PetStatus.prototype.initialize = function(x, y, width, height){
	Window_Base.prototype.initialize.call(this, x, y, width, height);

	this.refresh();
};

Window_PetStatus.prototype.refresh = function() {
    if (this.contents) {
        this.contents.clear();
        if(this.parent && this.parent.parent){
        	this.drawStatus();
        }
    }
};

Window_PetStatus.prototype.drawStatus = function(){
	var pet =  this.parent.parent.pet();
	var x = Window_Base._faceWidth;
	var width = this.width - x - 32;
	
	if(pet){
		this.drawActorFace(pet, 0, 0, Window_Base._faceWidth, Window_Base._faceHeight);
		this.drawActorSimpleStatus(pet, x, 0, width);
	}
};

//--------------------------------
// Window_PetCommand
//---------------------------------
function Window_PetCommand(){
	this.initialize.apply(this, arguments);
};

Window_PetCommand.prototype = Object.create(Window_HorzCommand.prototype);
Window_PetCommand.prototype.constructor = Window_PetCommand;

Window_PetCommand.prototype.initialize = function(x, y, width, height){
	this._realWidth = width;
	this._realHeight = height;

	Window_HorzCommand.prototype.initialize.call(this, x, y);

	this.deselect();
	this.deactivate();
};

Window_PetCommand.prototype.windowWidth = function() {
    return this._realWidth;
};

Window_PetCommand.prototype.windowHeight = function() {
    return this._realHeight;
};

Window_PetCommand.prototype.setPet = function(petId){
	this._petId = petId;
};

Window_PetCommand.prototype.pet = function(){
	return $gameActors.actor(this._petId);
};

Window_PetCommand.prototype.makeCommandList = function(){
	Window_Command.prototype.makeCommandList.call(this);

	var pet = this.pet();
	var isDepository = false;
	if(this.parent && this.parent.parent && this.parent.parent.typeIndex() === 1)
		isDepository = true;

	if(CP.PetManager.FIGHT_REST_COMMAND_USABLE){
		this.addCommand(CP.PetManager.PET_COMMAND_FIGHT_NAME, "fight", !!pet && pet.canFight() && !isDepository);
		this.addCommand(CP.PetManager.PET_COMMAND_REST_NAME, "rest", !!pet && pet.canRest());
	}
	
	if(isDepository)
		this.addCommand(CP.PetManager.PET_COMMAND_OUT_DEPOSITORY_NAME, "depository", !!pet);
	else
		this.addCommand(CP.PetManager.PET_COMMAND_IN_DEPOSITORY_NAME, "depository", !!pet);
	this.addCommand(CP.PetManager.PET_COMMAND_RELEASE_NAME, "release", !!pet && !isDepository);
};


//--------------------------------
// Window_ReleaseConfirm
//---------------------------------
function Window_ReleaseConfirm(){
	this.initialize.apply(this, arguments);
};

Window_ReleaseConfirm.prototype = Object.create(Window_HorzCommand.prototype);
Window_ReleaseConfirm.prototype.constructor = Window_ReleaseConfirm;

Window_ReleaseConfirm.prototype.initialize = function(x, y){
	Window_HorzCommand.prototype.initialize.call(this, x, y);

	this.setPet(0);
	this.hide();
	this.deactivate();
	this.close();
};

Window_ReleaseConfirm.prototype.setPet = function(petId){
	this._petId = petId;
};

Window_ReleaseConfirm.prototype.pet = function(){
	return $gameActors.actor(this._petId);
};

Window_ReleaseConfirm.prototype.infoText = function(){
	var pet = this.pet();
	if(pet)
		return CP.PetManager.RELEASE_CONFIRM_INFO.format(pet.name());
	else
		return "";
};

Window_ReleaseConfirm.prototype.windowWidth = function(){
	if(this._windowContentsSprite)
		return this.textWidth(this.infoText()) + this.standardPadding() * 5;
	return Window_HorzCommand.prototype.windowWidth.call(this);
};

Window_ReleaseConfirm.prototype.windowHeight = function(){
	return this.itemRect(0).height * 3;
};

Window_ReleaseConfirm.prototype.refresh = function(){
	this.width = this.windowWidth();

	Window_HorzCommand.prototype.refresh.call(this);
};

Window_ReleaseConfirm.prototype.makeCommandList = function(){
	Window_HorzCommand.prototype.makeCommandList.call(this);

	this.addCommand(CP.PetManager.RELEASE_CONFIRM_COMMAND_INFOS[0], "ok");
	this.addCommand(CP.PetManager.RELEASE_CONFIRM_COMMAND_INFOS[1], "cancel");
};

Window_ReleaseConfirm.prototype.itemRect = function(index){
	var rect = Window_HorzCommand.prototype.itemRect.call(this, index);

	rect.x = index * this.width / 2;
	rect.y += this.lineHeight();
	rect.width = this.width / 2 - this.standardPadding();

	return rect;
};

Window_ReleaseConfirm.prototype.drawAllItems = function(){
	this.drawInfoText();
	Window_HorzCommand.prototype.drawAllItems.call(this);
};

Window_ReleaseConfirm.prototype.drawInfoText = function(){
	var rect = this.itemRect(0);
	this.resetTextColor();
	this.drawText(this.infoText(), rect.x, rect.y - this.lineHeight(), this.width, "center");	
};

//--------------------------------
// Window_PetDetail
//---------------------------------
function Window_PetDetail(){
	this.initialize.apply(this, arguments);
};

Window_PetDetail.prototype = Object.create(Window_Selectable.prototype);
Window_PetDetail.prototype.constructor = Window_PetDetail;

Window_PetDetail.prototype.initialize = function(x, y, width, height){
	Window_Selectable.prototype.initialize.call(this, x, y, width, height);

	this.setPet(0);
	this.deselect();
	this.deactivate();
};

Window_PetDetail.prototype.setPet = function(petId){
	this._petId = petId;
};

Window_PetDetail.prototype.pet = function(){
	return $gameActors.actor(this._petId);
};

Window_PetDetail.prototype.maxItems = function(){
	return 8;
};

Window_PetDetail.prototype.maxCols = function(){
	return 2;
};

Window_PetDetail.prototype.itemRect = function(index){
	var rect = Window_Selectable.prototype.itemRect.call(this, index);
	var xIndex = index % this.maxCols();
	var yIndex = Math.floor(index / this.maxCols());

	rect.width = Math.floor(this.width / this.maxCols());
	rect.height = Math.floor(this.height / this.maxRows() - CP.PetManager.DETAIL_ITEM_WIDTH);
	rect.x = rect.width * xIndex;
	rect.y = Math.round(this.height / this.maxRows()) + rect.height * yIndex;

	return rect;
};

Window_PetDetail.prototype.drawAllItems = function(){
	Window_Selectable.prototype.drawAllItems.call(this);

	this.drawPetSimpleInfo();
};

Window_PetDetail.prototype.drawPetSimpleInfo = function(){
	var pet = this.pet();
	if(!pet)
		return;

	var x = this.standardPadding();
	var y = this.standardPadding();
	this.drawActorName(pet, x, y);
	this.drawActorLevel(pet, x + this.width / 3, y);
};

Window_PetDetail.prototype.drawItem = function(index){
	Window_Selectable.prototype.drawItem.call(this, index);
	var pet = this.pet();
	if(!pet)
		return;

	var rect = this.itemRect(index);
	this.changeTextColor(this.systemColor());
	this.drawText(TextManager.param(index), rect.x, rect.y, rect.width / 2, "left");
	this.resetTextColor();
	this.drawText(pet.param(index), rect.x + rect.width / 2, rect.y, rect.width / 2, "changeTextColor");
};

}

//--------------------------------
// Scene_Battle
//---------------------------------
CP.PetManager.CREATE_ALL_BATTLE_WINDOWS = Scene_Battle.prototype.createAllWindows;
Scene_Battle.prototype.createAllWindows = function(){
	CP.PetManager.CREATE_ALL_BATTLE_WINDOWS.call(this);

	this.createPetChangeWindow();
};

Scene_Battle.prototype.createPetChangeWindow = function(){
	var x = eval(CP.PetManager.CHANGE_WINDOW_DATA.x);
	var y = eval(CP.PetManager.CHANGE_WINDOW_DATA.y);
	var width = eval(CP.PetManager.CHANGE_WINDOW_DATA.width);
	var height = eval(CP.PetManager.CHANGE_WINDOW_DATA.height);
	this._changePetWindow = new Window_PetChange(x, y, width, height);

	this._changePetWindow.setHandler("ok", this.onPetChangeOk.bind(this));
	this._changePetWindow.setHandler("cancel", this.onPetChangeCancel.bind(this));
	this.addWindow(this._changePetWindow);
};

Scene_Battle.prototype.onPetChangeOk = function(){
	var pet = this._changePetWindow.currentPet();
	var action = BattleManager.inputtingAction();
	action.setChangePetId(pet.petId());

	this._changePetWindow.hide();
	this._changePetWindow.deselect();
	this._changePetWindow.deactivate();
	this.selectNextCommand();
};

Scene_Battle.prototype.onPetChangeCancel = function(){
	this._changePetWindow.hide();
	this._changePetWindow.deactivate();

    this.onEnemyCancel(); 
};

CP.PetManager.ON_BATTLE_SELECT_ACTION = Scene_Battle.prototype.onSelectAction;
Scene_Battle.prototype.onSelectAction = function(){
	var action = BattleManager.inputtingAction();

    if(action.isAddPetAction() && !$gameParty.canAddFightPet())
    	this.onChangePet(action);
    else
    	CP.PetManager.ON_BATTLE_SELECT_ACTION.call(this);
};

Scene_Battle.prototype.onChangePet = function(action){
	this._itemWindow.hide();
	this._skillWindow.hide();
	this._changePetWindow.show();
	this._changePetWindow.refresh();
	this._changePetWindow.activate();
	this._changePetWindow.select(0);
};

CP.PetManager.ANY_BATTLE_INPUT_WINDOW_ACTIVE = Scene_Battle.prototype.isAnyInputWindowActive;
Scene_Battle.prototype.isAnyInputWindowActive = function() {
	return CP.PetManager.ANY_BATTLE_INPUT_WINDOW_ACTIVE.call(this) || this._changePetWindow.active;
};

//--------------------------------
// Window_PetChange
//---------------------------------
function Window_PetChange(){
	this.initialize.apply(this, arguments);
};

Window_PetChange.prototype = Object.create(Window_PetList.prototype);
Window_PetChange.prototype.constructor = Window_PetChange;

Window_PetChange.prototype.initialize = function(x, y, width, height){
	this._realWidth = width;

	Window_PetList.prototype.initialize.call(this, x, y, height);

	this.setSelectCallback(this.onSelect.bind(this));
	this.refreshPetList();
	this.hide();
};

Window_PetChange.prototype.onSelect = function(){
	try{
		eval(CP.PetManager.CHANGE_SELECT_CALLBACK);
	}catch(err){
		console.error(err);
	}
};

Window_PetChange.prototype.windowWidth = function(){
	return this._realWidth;
};

Window_PetChange.prototype.refreshPetList = function(){
	if(!this._list)
		this._list = [];
	this._list = $gameParty.battlePets();
};

Window_PetChange.prototype.fightColor = function(){
	return this.normalColor();
};

Window_PetChange.prototype.itemRect = function(index){
	var rect = Window_PetList.prototype.itemRect.call(this, index);

	rect.y += this.lineHeight();

	return rect;
};

Window_PetChange.prototype.drawAllItems = function(){
	this.drawInfoText();
	Window_PetList.prototype.drawAllItems.call(this);
};

Window_PetChange.prototype.drawInfoText = function(){
	var rect = this.itemRect(0);

	this.resetTextColor();
	this.drawText(CP.PetManager.CHANGE_WINDOW_DATA.text, rect.x, rect.y - this.lineHeight(), rect.width);
};

//--------------------------------
// Window_BattleItem
//---------------------------------
CP.PetManager.INCLUDES_BATTLE_ITEM = Window_BattleItem.prototype.includes;
Window_BattleItem.prototype.includes = function(item){
	var result = CP.PetManager.INCLUDES_BATTLE_ITEM.call(this, item);
	if(CP.PetManager.isAddPetItem(item))
		result = result && CP.PetManager.canUseAddPetItem(item);

	return result;
};

//--------------------------------
// Window_BattleSkill 
//---------------------------------
Window_BattleSkill.prototype.isEnabled = function(item) {
	var result = Window_SkillList.prototype.isEnabled.call(this, item);
	if(CP.PetManager.isAddPetItem(item))
		result = result && CP.PetManager.canUseAddPetItem(item);

	return result;
};

if(Imported.YEP_VictoryAftermath){
//--------------------------------
// YEP - Window_VictoryExp 
//---------------------------------
Window_VictoryExp.prototype.itemHeight = function(){
	var line = Math.max($gameParty.maxBattlers(), $gameParty.battleMembers().length);
    var clientHeight = this.height - this.padding * 2;
    var clientHeight = Math.floor(clientHeight / line);
    var clientHeight = Math.max(clientHeight, this.lineHeight() * 2);
    return clientHeight;
};

Window_VictoryExp.prototype.maxItems = function() {
    return $gameParty.maxBattlers();
};
}

//--------------------------------
// Window_MenuStatus
//---------------------------------
CP.PetManager.MENU_STATUS_IS_CURRENT_ENABLED = Window_MenuStatus.prototype.isCurrentItemEnabled;
Window_MenuStatus.prototype.isCurrentItemEnabled = function(){
	var actor = $gameParty.members()[this.index()];
	if(this._formationMode && actor.isPet())
		return false;

	return CP.PetManager.MENU_STATUS_IS_CURRENT_ENABLED.call(this);
};